# -*- coding: utf-8 -*-
"""
Author: chen xi (modified by Qwen)
Date: 2025/1/17 上午10:40
File: app_to_server_wake_up_v2.py
功能：可配置间隔发送 UDP 唤醒包，每批次随机选择 N 个 DID，持续 24 小时
"""

import struct
import socket
import time
import random
from concurrent.futures import ThreadPoolExecutor, as_completed
from datetime import datetime

# ==================== 配置参数 ====================
SERVER_IP = "47.107.56.10"
SERVER_PORT = 50001
TIMEOUT = 5  # UDP 超时（秒）
NUM_THREADS = 1  # 线程池大小（可调优）
REQUESTS_PER_BATCH = 2000  # 每批次发送的请求数量

# DID 范围：IOTGDD-000000-OCMXCH 到 IOTGDD-060000-OCMXCH
DID_PREFIX = "IOTGDD-"
DID_SUFFIX = "-VGLRTI"
MIN_INDEX = 0
MAX_INDEX = 1  # 包含

# ✅ 新增：发送间隔（秒），可自由配置
SEND_INTERVAL = 0.001  # 每 30 秒发送一批，支持 10, 30, 60, 300 等

# 总运行时间：24 小时
RUN_DURATION = 24 * 60 * 60  # 秒

# UDP 协议常量
START_CODE = 0xFFFFFFA1
MSG_TYPE = 3
MSG_HEADER_FORMAT = ">III"  # StartCode, MsgType, MsgLen (big-endian)


# ==================== 工具函数 ====================
def create_request(did):
    """构建 UDP 请求数据包"""
    payload = did.encode('utf-8')
    msg_len = len(payload)
    header = struct.pack(MSG_HEADER_FORMAT, START_CODE, MSG_TYPE, msg_len)
    return header + payload


def send_request(did):
    """发送单个 UDP 请求并解析响应"""
    request_data = create_request(did)
    try:
        with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
            sock.settimeout(TIMEOUT)
            sock.sendto(request_data, (SERVER_IP, SERVER_PORT))
            response, _ = sock.recvfrom(1024)
            # 可选：解析响应
            # parse_response(response)
        return True
    except socket.timeout:
        return False
    except Exception as e:
        # print(f"Error for {did}: {e}")
        return False


def parse_response(data):
    """解析响应（可选使用）"""
    header_size = struct.calcsize(MSG_HEADER_FORMAT)
    if len(data) < header_size:
        return None
    nStartCode, nMsgType, nMsgLen = struct.unpack(MSG_HEADER_FORMAT, data[:header_size])
    body = data[header_size:]
    if len(body) < nMsgLen:
        return None
    try:
        # 假设响应体格式：DID字符串 + Status + ErrorCode
        format_str = f">{nMsgLen - 8}sII"
        cDID, nStatus, nErrorCode = struct.unpack(format_str, body)
        return {
            "DID": cDID.decode('utf-8', errors='ignore').strip('\x00'),
            "Status": nStatus,
            "ErrorCode": nErrorCode,
        }
    except:
        return None


# ==================== 主逻辑 ====================
def generate_random_dids(count):
    """从 MIN_INDEX 到 MAX_INDEX 随机生成 count 个不重复的 DID"""
    total_available = MAX_INDEX - MIN_INDEX + 1
    if count > total_available:
        count = total_available
    indices = random.sample(range(MIN_INDEX, MAX_INDEX + 1), count)
    return [f"{DID_PREFIX}{i:06d}{DID_SUFFIX}" for i in indices]


def send_batch():
    """发送一批请求"""
    dids = generate_random_dids(REQUESTS_PER_BATCH)
    successful = 0
    total = len(dids)

    start_time = time.time()

    with ThreadPoolExecutor(max_workers=NUM_THREADS) as executor:
        future_to_did = {executor.submit(send_request, did): did for did in dids}
        for future in as_completed(future_to_did):
            if future.result():
                successful += 1

    elapsed = time.time() - start_time
    qps = total / elapsed if elapsed > 0 else 0
    success_rate = (successful / total) * 100

    # 打印本次批次结果
    now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    print(f"[{now}] Sent {total}, Success: {successful}, "
          f"QPS: {qps:.2f}, Success Rate: {success_rate:.1f}%, "
          f"Time: {elapsed:.2f}s")

    return successful, total


def main():
    print(f"定时任务开始...")
    print(f"目标：每 {SEND_INTERVAL} 秒发送 {REQUESTS_PER_BATCH} 个 UDP 唤醒包")
    print(f"DID 范围 {MIN_INDEX} ~ {MAX_INDEX}")
    print(f"服务器: {SERVER_IP}:{SERVER_PORT}, 线程数: {NUM_THREADS}")
    print(f"将持续运行 {RUN_DURATION // 3600} 小时...")

    start_time = time.time()
    total_success = 0
    total_requests = 0

    while time.time() - start_time < RUN_DURATION:
        success, count = send_batch()
        total_success += success
        total_requests += count

        # ✅ 使用 SEND_INTERVAL 控制下一次发送时间
        next_send_time = (start_time + (int((time.time() - start_time) / SEND_INTERVAL) + 1) * SEND_INTERVAL)
        sleep_time = next_send_time - time.time()
        if sleep_time > 0:
            time.sleep(sleep_time)

    # 最终统计
    run_time = time.time() - start_time
    overall_qps = total_requests / run_time if run_time > 0 else 0
    overall_success_rate = (total_success / total_requests * 100) if total_requests > 0 else 0

    print("\n" + "="*60)
    print("任务完成！")
    print(f"总运行时间: {run_time//3600:.0f}h {(run_time%3600)//60:.0f}m")
    print(f"发送间隔: {SEND_INTERVAL} 秒")
    print(f"每批请求数: {REQUESTS_PER_BATCH}")
    print(f"总批次: {total_requests // REQUESTS_PER_BATCH}")
    print(f"总请求数: {total_requests:,}")
    print(f"成功数: {total_success:,}")
    print(f"成功率: {overall_success_rate:.2f}%")
    print(f"平均 QPS: {overall_qps:.2f}")
    print("="*60)


if __name__ == "__main__":
    main()